package main

import (
	"database/sql"
	"encoding/json"
	"errors"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"io/ioutil"
	"net/http"
	"regexp"

	//"regexp"
	"strconv"
	"strings"
	"time"
)

const (
	host = "127.0.0.1"
	port = "3306"
	db_name = "golang"
	user = "root"
	password = ""
	limit = "50"

)
var DB *sql.DB
func main() {
	InitDB()
	//1.获取豆瓣电影标签		入库	get
	//GetDouBanTags()
	//2.获取豆瓣标签对应电影	入库	get
	//GetMovesFroUrl()
	//3.获取电影详情
	GetMovesInfo()
	DB.Close()
	//演员&导演&编辑 列表
	//https://movie.douban.com/subject/26887055/celebrities
	//演员&导演&编辑 详情
	//https://movie.douban.com/celebrity/1051327/
	//艺人作品列表
	//https://movie.douban.com/celebrity/1312877/movies?start=0&format=pic&sortby=time&
	//电影影评列表
	//https://movie.douban.com/subject/26710657/comments?start=20&limit=20&sort=new_score&status=P
	//艺人获奖情况
	//https://movie.douban.com/celebrity/1282536/awards/
}
//获取电影详情
func GetMovesInfo(){
	id := 0
	for id<=217825 {
		urls := GetMoveInfoLink(id)
		if len(urls)==0 {
			fmt.Println("nil")
			break
		}
		for _,v := range urls{
			url := "https://movie.douban.com/subject/"+v["dou_id"]
			id,_ = strconv.Atoi(v["id"])
			html,err := httpGetResult(url)
			if err != nil{
				panic(err)
			}
			//regx := `[[:^ascii:]]+` 匹配所以非ascii值的数据[汉字 标点]
			//1.1 获取电影详情 info 部分html
			regx := `<div id="info">[\s\S[:^ascii:]]+<div id="interest_sectl">`
			reg := regexp.MustCompile(regx)
			data := reg.FindAll(html,1)
			//1.2 匹配详情中标签内的中文字符串
			regx = `>\S{0,}[[:^ascii:]]{0,}\s?<`
			reg = regexp.MustCompile(regx)
			values := reg.FindAllSubmatch(data[0],-1)
			//insertData := make(map[int]map[string]string)
			insertStr := ""
			key := ""
			subMap := make(map[string]string)
			subMap["movie_id"] = v["dou_id"]
			for _,val := range values{
				for _,vals := range val{
					re, _ := regexp.Compile(`span|a|>|<`)
					str := string(vals[:])
					str = re.ReplaceAllString(str,"")
					str = strings.Trim(str,": ")
					str = strings.Trim(str,"/")
					str = strings.Trim(str,": ")
					if str != ""{
						insertStr = insertMoveInfo(str)
						if insertStr != ""{
							key = insertStr
							continue
						}
						if key != ""{
							subMap[key] += str+"/"
						}
					}
				}


			}
			sql,err := GetInsertSqlByMap(subMap,"go_movie_info",1)
			if err != nil {
				panic(err)
			}
			fmt.Println(sql)
			sqlRes,err := InsertSql(sql)
			if err != nil{
				panic(err)
			}
			fmt.Println(sqlRes+v["id"])
			id,_ = strconv.Atoi(v["id"])
			//x := rand.Intn(100)
			//time.Sleep(time.Duration(x) * time.Second)
		}
	}
}
func insertMoveInfo(title string) (string){
	field := map[string]string{"导演":"","编剧":"","主演":"","类型":"movie_type","官方网站":"movie_site","语言":"movie_lang",
	"制片国家/地区":"country","上映日期":"show_time","片长":"movie_time","又名":"other_name","IMDb链接":"imdb_link"}
	if field[title] != ""{
		return field[title]
	}else{
		return ""
	}
}
//获取接口地址返回的电影json字符串
func GetMovesFroUrl(){
	//获取标签对应电影接口地址
	urls := GetTagsToMoveLink()
	for _,v := range urls{
		page := 0
		for page >=0 {
			all,err := httpGetResult(v+strconv.Itoa(page))
			if err != nil{
				panic(err)
			}
			data := map[string] interface{}{}
			//var MoveRes map[int]map[string]string
			json.Unmarshal(all,&data)
			//需要入库的字段
			field := "dou_id,move_name,move_url,move_rate,poster_url,poster_max_x,poster_max_y,is_new,create_time"
			//json中与field字段对应位置key集合
			jsons := map[int]string{0:"id",1:"title",2:"url",3:"rate",4:"cover",5:"cover_x",6:"cover_y",7:"is_new"}
			//获取insert sql
			sql,err := GetInsertSqlByJson(data["subjects"],"go_moves",field,jsons,1)
			if err != nil {
				panic(err)
			}
			if sql=="" {
				break
			}
			//执行sql
			result,err := InsertSql(sql)
			if err != nil{
				panic(err)
			}
			fmt.Println(result)
			page++
		}

	}
}
//执行insert sql语句
func InsertSql(sql string)(res string,error error){
	result, err := DB.Exec(sql)
	if err !=nil{
		return "",err
	}
	if  _,err := result.LastInsertId();err ==nil {
		return "",err
	}
	return "sucess",nil
}
//通过json对象湖区insert sql
//data->json对象
//table->表名
//field->入库字段
//jsons->json对象种与field对应位置key
//times->是否需要增加时间戳， 1=是/0=否
func GetInsertSqlByJson(data interface{},table string,field string,jsons map[int]string,times int) (sql string,error error){
	if table=="" || field=="" {
		return "",errors.New("empty table or fiele")
	}
	sql = "insert into "+table+" ("+field+") values "
	switch js_data := data.(type) {
		case int:
			fmt.Println("int")
		case string:
			fmt.Println("string")
		case []string:
			fmt.Println("map[\"string\"]")
		case []interface{}:
			if len(js_data)<=0 {
				return "",nil
			}
			fmt.Println(len(js_data))
			len := len(jsons)
			for _,v := range js_data {
				if(len > 0){
					vs := v.(map[string]interface{})

					sql += "("
					for i:=0;i<len;i++ {
						sql += "\""+InterfaceString(vs[jsons[i]])+"\","
					}
				}else{
					sql += "('"+v.(string)+"',"
				}
				if times==1{
					t := time.Now().Unix()
					sql += "'"+strconv.FormatInt(t,10)+"'),"
				}else{
					sql = strings.Trim(sql,",")+"),"
				}
			}
		default:
			fmt.Println(js_data)
			fmt.Println("undefined")
	}
	return strings.Trim(sql,","),nil
}

func GetInsertSqlByMap(data map[string]string,table string,times int)(string,error){
	if table==""{
		return "",errors.New("empty table or fiele")
	}
	sql,field := "(",""
	for k,v := range data{
		field += k+","
		sql += "'"+strings.Trim(v,"/")+"',"
	}
	if times==1{
		field += "create_time"
		t := time.Now().Unix()
		sql += "'"+strconv.FormatInt(t,10)+"')"
	}else{
		field += strings.Trim(field,",")
		sql = strings.Trim(sql,",")+")"
	}
	rs := "insert into "+table+" ("+field+") values "+sql
	return rs,nil
}
//将interface转为string
func InterfaceString(data interface{})string{
	str := ""
	if _, ok := data.(bool); ok{
		if data==true{
			str = "1"
		}else{
			str = "0"
		}
	}else if _, ok := data.(float64); ok{
		str = strconv.FormatFloat(data.(float64), 'E', -1, 64)
	}else if _, ok := data.(string); ok{
		str = data.(string)
	}
	return str
}
//获取标签对应电影集合的接口地址
func GetTagsToMoveLink() map[int]string{
	//1.获取标签表所有标签
	MoveUrl := make(map[int]string)
	sql := "select tags_name from go_tags order by tags_id asc"
	res := getSelectData(sql)
	//2.拼接douban标签对应电影集合地址
	for k,val := range res{
		for _,v := range val{
			MoveUrl[k] = "https://movie.douban.com/j/search_subjects?type=movie&tag="+v+"&sort=recommend&page_limit="+limit+"&page_start="
		}
	}
	return MoveUrl
}

//获取电影详情链接集合
func GetMoveInfoLink(id int)map[int]map[string]string{
	Url := make(map[int]map[string]string)
	sql := "select id,dou_id from go_moves where id>"+strconv.Itoa(id)+" order by id asc limit 10"
	res := getSelectData(sql)
	for k,val := range res{
		Url[k] = val
	}
	return Url
}
//MySQL select 方法
func getSelectData(sql string) map[int]map[string]string{
	rows2, _ := DB.Query(sql)
	defer rows2.Close()
	//返回所有列
	cols, _ := rows2.Columns()
	//这里表示一行所有列的值，用[]byte表示
	vals := make([][]byte, len(cols))
	//这里表示一行填充数据
	scans := make([]interface{}, len(cols))
	//这里scans引用vals，把数据填充到[]byte里
	for k, _ := range vals {
		scans[k] = &vals[k]
	}

	i := 0
	result := make(map[int]map[string]string)
	for rows2.Next() {
		//填充数据
		rows2.Scan(scans...)
		//每行数据
		row := make(map[string]string)
		//把vals中的数据复制到row中
		for k, v := range vals {
			key := cols[k]
			//这里把[]byte数据转成string
			row[key] = string(v)
		}
		//放入结果集
		result[i] = row
		i++
	}
	return result
}
//获取豆瓣电影标签
func GetDouBanTags(){
	url := "https://movie.douban.com/j/search_tags?type=movie&source="
	all, err := httpGetResult(url)
	if err != nil{
		panic(err)
	}
	//定义一个保存json对象的data
	var data map[string] interface{}
	//将json字符串转为json对象，并保存在data中
	json.Unmarshal(all,&data)
	field := "tags_name,create_time"
	jsons := map[int]string{}

	sql,err := GetInsertSqlByJson(data["tags"],"go_tags",field,jsons,1)
	if err !=nil{
		panic(err)
	}
	result, err := InsertSql(sql)
	if err !=nil{
		panic(err)
	}
	fmt.Println(result)
}
//链接数据库
func InitDB() {
	path := strings.Join([]string{user, ":", password, "@tcp(",host, ":", port, ")/", db_name, "?charset=utf8"}, "")
	DB,_ = sql.Open("mysql",path)
	DB.SetConnMaxLifetime(100)
	DB.SetMaxIdleConns(10)
	if err := DB.Ping(); err != nil{
		panic("opon database fail")
		return
	}
}
//http_get请求地址
func httpGetResult(url string) ([]byte,error){
	fmt.Println(url)
	if url == ""{
		return []byte(""),errors.New("没有要请求的url")
	}
	res,err :=http.Get(url)
	if err != nil{
		return []byte(""),err
	}
	defer res.Body.Close()
	all,err := ioutil.ReadAll(res.Body)
	if err != nil{
		return []byte(""),err
	}
	return all,nil
}

func ReadFile(path string) ([]byte,error){
	if path ==""{
		return []byte(""),errors.New("不存在这个文件")
	}
	info,err := ioutil.ReadFile(path)
	if err != nil {
		return []byte(""),err
	}

	return info,nil
}

//获取电影评论
func GetMoveComments(){

	// span class=comment-vote -> span class=votes -> value 点赞数

	//allstar50=5星 allstar20=2星
	// span class=comment-info -> a 找到用户昵称 用户id
	// span class=comment-info -> comment-time ->title 发布时间
	// span class=comment-info -> span class=allstar50 找到用户昵称 用户id

	//想看电影
	// https://movie.douban.com/subject/30414462/comments?start=0&limit=20&sort=new_score&status=F

	//看过电影
	// https://movie.douban.com/subject/30414462/comments?start=0&limit=20&sort=new_score&status=P

}